﻿using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;

namespace Nemerle.Data
{
  #warning not tested
  
  public variant LazyIterator[T] : IEnumerable[T]
  {
    | Cons { head : T; mutable tail : LazyIterator[T] }
    | InitCell { mutable tail : LazyIterator[T] }
    | Enumerator { en : IEnumerator[T] }
    | Nil { public override ToString() : string { "[]" } }
    
    public Tail() : LazyIterator[T]
    {
      match(this){
        | Cons(_, t) => t
        | InitCell(t)=> t.Tail()
        | _          => throw Exception()
      }
    }
    
    public override ToString() : string
    {
      def loop(l, s){
        match(l){
          | InitCell(t)   => loop(t, s) 
          | Cons(h, t)    => loop(t, s.Append(h.ToString()).Append(", "))
          | Enumerator(_) => s.Append("...")
          | Nil()         => s
        }
      }
      loop(this, Text.StringBuilder().Append("[")).Append("]").ToString()
    }
    
    public static ToLazy(this seq : IEnumerable[T]) : IEnumerable[T]
    {
      using (e = seq.GetEnumerator())
      {
        InitCell(Enumerator(e))
      }
    }
    
    public GetEnumerator() : IEnumerator[T]
    {
      def loop(l) {
        | Cons(h, t) as c => { 
          yield h; 
          match(t) {
            | Enumerator(e) => { 
               c.tail = if(e.MoveNext()) Cons(e.Current, t) else Nil(); 
               loop(c.tail) 
             }
            | _ => loop(t) 
          } 
        }
        | Nil()       => ()
        | InitCell(t)  as init => match(t) {
          | Enumerator(e) => { 
               init.tail = if(e.MoveNext()) Cons(e.Current, t) else Nil(); 
               loop(init.tail) 
             }
          | _ => loop(t) 
        }
      }
      //and next(l, t) {
      //  match(t) {
      //    | Enumerator(e) => { 
      //         c.tail = if(e.MoveNext()) Cons(e.Current, t) else Nil(); 
      //         loop(t) 
      //       }
      //    | _ => loop(t) 
      //  }
      //}
      loop(this)
    }
  }
}
